home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / HPACK78S.ZIP / os2.c < prev    next >
C/C++ Source or Header  |  1992-12-02  |  41KB  |  1,511 lines

  1. /****************************************************************************
  2. *                                                                            *
  3. *                            HPACK Multi-System Archiver                        *
  4. *                            ===========================                        *
  5. *                                                                            *
  6. *                              OS/2-Specific Routines                        *
  7. *                              OS2.C  Updated 04/08/92                        *
  8. *                                                                            *
  9. * This program is protected by copyright and as such any use or copying of    *
  10. *  this code for your own purposes directly or indirectly is highly uncool    *
  11. *                      and if you do so there will be....trubble.                *
  12. *                 And remember: We know where your kids go to school.            *
  13. *                                                                            *
  14. *            Copyright 1991 - 1992  Conrad Bullock and John Burnell            *
  15. *                                All rights reserved                            *
  16. *                                                                            *
  17. ****************************************************************************/
  18.  
  19. /* This file contains a the code for both the 16 and 32-bit versions of
  20.    OS/2.  There is a fair amount of dual-use code, as well as some version-
  21.    specific routines, toggled by defining OS2_32 */
  22.  
  23. #define INCL_BASE
  24. #if defined( __TSC__ )
  25.   #define BYTE    OS2_BYTE
  26.   #include <os2pm.h>
  27.   #undef BYTE
  28.   #undef COMMENT
  29. #elif defined( OS2_32 )
  30.   #define INCL_BASE
  31.   #define INCL_NOPMAPI
  32.   #define BYTE    OS2_BYTE
  33.  
  34.   #include <os2.h>
  35.   #undef BYTE
  36. #else
  37.   #include <os2.h>
  38. #endif /* __TSC__ */
  39.  
  40. #undef LONG
  41.  
  42. #ifdef __TSC__
  43.   #include <alloc.h>
  44. #endif /* __TSC__ */
  45. #include <ctype.h>
  46. #ifdef __TSC__
  47.   #include <dir.h>
  48. #endif /* __TSC__ */
  49. #ifndef OS2_32
  50.   #include <io.h>
  51. #endif /* OS2_32 */
  52. #include <stdio.h>
  53. #include <stdlib.h>
  54. #include <string.h>
  55. #include <time.h>
  56. #include "defs.h"
  57. #include "arcdir.h"
  58. #include "frontend.h"
  59. #include "system.h"
  60. #include "wildcard.h"
  61. #include "hpacklib.h"
  62. #include "crc/crc16.h"
  63. #include "io/fastio.h"
  64.  
  65. #ifndef OS2_32
  66.  
  67. /* Prototypes for memory-management functions */
  68.  
  69. void far *farmalloc( unsigned long num );
  70. void far *farrealloc( void far *block, unsigned long num );
  71. void farfree( void far *block );
  72. #endif /* OS2_32 */
  73.  
  74. /* Whether this file is being added from an HPFS drive or not */
  75.  
  76. BOOLEAN isHPFS = FALSE;
  77. BOOLEAN destIsHPFS = FALSE;
  78.  
  79. /* The drive the archive is on */
  80.  
  81. BYTE archiveDrive;
  82.  
  83. /* Get an input char, no echo */
  84.  
  85. int hgetch( void )
  86.     {
  87. #ifdef OS2_32
  88.     return _read_kbd( 0, 1, 1 );
  89. #else
  90.     return( getch() );
  91. #endif /* OS2_32 */
  92.     }
  93.  
  94. /****************************************************************************
  95. *                                                                            *
  96. *                                HPACKLIB Functions                            *
  97. *                                                                            *
  98. ****************************************************************************/
  99.  
  100. /* Memory management functions.  The OS2_32 ones could be aliased in
  101.    hpacklib.h since under OS/2 2.0 we don't have the memory limitations of
  102.    the 16-bit versions of OS/2, but to be consistent we implement them as
  103.    wrappers for the std. library calls as in the 16-bit version */
  104.  
  105. #ifdef OS2_32
  106. void *hmalloc( const unsigned long size )
  107.     {
  108.     return( malloc( size ) );
  109.     }
  110.  
  111. void *hrealloc( void *buffer, const unsigned long size )
  112.     {
  113.     return( realloc( buffer, size ) );
  114.     }
  115.  
  116. void hfree( void *buffer )
  117.     {
  118.     free( buffer );
  119.     }
  120. #else
  121.  
  122. void *hmalloc( const unsigned long size )
  123.     {
  124.     if( size > 0xFFFF )
  125.         /* Farm alloc?  Out of pasture space - don't have a cow man */
  126.         return( farmalloc( size ) );
  127.     else
  128.         return( malloc( ( int ) size ) );
  129.     }
  130.  
  131. void *hrealloc( void *buffer, const unsigned long size )
  132.     {
  133.     if( size > 0xFFFF )
  134.         return( farrealloc( buffer, size ) );
  135.     else
  136.         return( realloc( buffer, ( int ) size ) );
  137.     }
  138.  
  139. void hfree( void *buffer )
  140.     {
  141.     free( buffer );
  142.     }
  143. #endif /* OS2_32 */
  144.  
  145. /****************************************************************************
  146. *                                                                            *
  147. *                                HPACKIO Functions                            *
  148. *                                                                            *
  149. ****************************************************************************/
  150.  
  151. /* Functions to open and create files in binary mode */
  152.  
  153. int hopen( const char *fileName, const int mode )
  154.     {
  155.     HFILE hFile;
  156. #ifdef OS2_32
  157.     ULONG action;
  158. #else
  159.     USHORT action;
  160. #endif /* OS2_32 */
  161.  
  162.     return( ( DosOpen( ( PSZ ) fileName, &hFile, &action, 0, \
  163.                        FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS, mode, 0 ) == NO_ERROR ) ? \
  164.             hFile : IO_ERROR );
  165.     }
  166.  
  167. int hcreat( const char *fileName, const int attr )
  168.     {
  169.     HFILE hFile;
  170. #ifdef OS2_32
  171.     ULONG action;
  172. #else
  173.     USHORT action;
  174. #endif /* OS2_32 */
  175.  
  176.     return( ( DosOpen( ( PSZ ) fileName, &hFile, &action, 0, FILE_NORMAL, \
  177.                        OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS, \
  178.                        attr, 0 ) == NO_ERROR ) ? hFile : IO_ERROR );
  179.     }
  180.  
  181. /* Close a file */
  182.  
  183. int hclose( const FD theFD )
  184.     {
  185.     return( ( DosClose( theFD ) == NO_ERROR ) ? OK : IO_ERROR );
  186.     }
  187.  
  188. /* Create a directory */
  189.  
  190. int hmkdir( const char *dirName, const int attr )
  191.     {
  192. #ifdef OS2_32
  193.     return( ( DosCreateDir( ( PSZ ) dirName, 0 ) == NO_ERROR ) ? OK : IO_ERROR );
  194. #else
  195.     return( ( mkdir( dirName ) == NO_ERROR ) ? OK : IO_ERROR );
  196. #endif
  197.     }
  198.  
  199. /* Seek to a specified position in a file, and return the current position
  200.    in a file */
  201.  
  202. long hlseek( const FD theFD, const long position, const int whence )
  203.     {
  204.     LONG where;
  205.  
  206. #ifdef OS2_32
  207.     return( ( DosSetFilePtr( theFD, position, whence, &where ) == NO_ERROR ) ? \
  208.             where : IO_ERROR );
  209. #else
  210.     return( ( DosChgFilePtr( theFD, position, whence, &where ) == NO_ERROR ) ? \
  211.             where : IO_ERROR );
  212. #endif
  213.     }
  214.  
  215. long htell( const FD theFD )
  216.     {
  217.     ULONG where;
  218.  
  219. #ifdef OS2_32
  220.     if( DosSetFilePtr( theFD, 0L, FILE_CURRENT, &where ) != NO_ERROR )
  221. #else
  222.     if( DosChgFilePtr( theFD, 0L, FILE_CURRENT, &where ) != NO_ERROR )
  223. #endif
  224.         return( IO_ERROR );
  225.     return( where );
  226.     }
  227.  
  228. /* Read/write a specified amount of data from/to a file */
  229.  
  230. int hread( const FD inFD, void *buffer, const unsigned int bufSize )
  231.     {
  232. #ifdef OS2_32
  233.     ULONG bytesRead;
  234. #else
  235.     USHORT bytesRead;
  236. #endif /* OS2_32 */
  237.  
  238.     return( ( DosRead( inFD, buffer, bufSize, &bytesRead ) == NO_ERROR ) ? \
  239.             ( int ) bytesRead : IO_ERROR );
  240.     }
  241.  
  242. int hwrite( const FD outFD, void *buffer, const unsigned int bufSize )
  243.     {
  244. #ifdef OS2_32
  245.     USHORT bytesWritten;
  246. #else
  247.     ULONG bytesWritten;
  248. #endif /* OS2_32 */
  249.     int bytesToWrite = bufSize;
  250.     FSALLOCATE fsAllocate;
  251.     ULONG SpaceAvail;
  252.     USHORT Result;
  253.  
  254.     if( DosWrite( outFD, buffer, bytesToWrite, &bytesWritten ) != NO_ERROR )
  255.         return( IO_ERROR );
  256.  
  257.     /* Fix the behaviour of DosWrite() by retrying the write with less data
  258.        if it fails (the DOS/OS2 write() is a boolean all-or-nothing affair
  259.        rather than doing the Right Thing as writing as much as it can) */
  260.     if( ( int ) bytesWritten != bytesToWrite )
  261.         {
  262. #ifdef OS2_32
  263.         if( DosQueryFSInfo( archiveDrive, FSIL_ALLOC, &fsAllocate, \
  264.                         sizeof( fsAllocate ) ) != NO_ERROR )
  265. #else
  266.         if( DosQFSInfo( archiveDrive, FSIL_ALLOC, &fsAllocate, \
  267.                         sizeof( fsAllocate ) ) != NO_ERROR )
  268. #endif
  269.             return( IO_ERROR );
  270.  
  271.         /* Calculate the disk space available and retry the write with that
  272.            amount */
  273.         SpaceAvail = fsAllocate.cUnitAvail * fsAllocate.cSectorUnit * fsAllocate.cbSector;
  274.         return( ( DosWrite( outFD, buffer, SpaceAvail, &bytesWritten ) == NO_ERROR) ? \
  275.                 bytesWritten : IO_ERROR );
  276.         }
  277.     else
  278.         return( bytesWritten );
  279.     }
  280.  
  281. /* Change a file's attributes */
  282.  
  283. int hchmod( const char *fileName, const WORD attr )
  284.     {
  285. #ifdef OS2_32
  286.     FILESTATUS3 fileInfo;
  287.  
  288.     if( DosQueryPathInfo( ( PSZ ) fileName, FIL_STANDARD, &fileInfo, \
  289.                           sizeof( fileInfo ) ) != NO_ERROR )
  290.         return( IO_ERROR );
  291.     fileInfo.attrFile = attr;
  292.     return( ( DosSetPathInfo( ( PSZ ) fileName, FIL_STANDARD, &fileInfo, \
  293.                               sizeof( fileInfo ), 0 ) == NO_ERROR ) ? \
  294.             OK : IO_ERROR );
  295. #else
  296.     return( DosSetFileMode( ( PSZ ) fileName, attr, 0L ) );
  297. #endif /* OS2_32 */
  298.     }
  299.  
  300. /* Delete a file */
  301.  
  302. int hunlink( const char *fileName )
  303.     {
  304. #ifdef OS2_32
  305.     return( ( DosDelete( ( PSZ ) fileName ) == NO_ERROR ) ? OK : IO_ERROR );
  306. #else
  307.     return( ( DosDelete( ( PSZ ) fileName, 0L ) == NO_ERROR ) ? OK : IO_ERROR );
  308. #endif
  309.     }
  310.  
  311. /* Rename a file */
  312.  
  313. int hrename( const char *srcName, const char *destName )
  314.     {
  315. #ifdef OS2_32
  316.     return( ( DosMove( ( PSZ ) srcName, ( PSZ ) destName ) == NO_ERROR ) ? OK : IO_ERROR );
  317. #else
  318.     return( ( DosMove( ( PSZ ) srcName, ( PSZ ) destName, 0L ) == NO_ERROR ) ? OK : IO_ERROR );
  319. #endif /* OS2_32 */
  320.     }
  321.  
  322. int htruncate ( const FD theFile )
  323.     {
  324.     ULONG FilePos;
  325.  
  326. #ifdef OS2_32
  327.     DosSetFilePtr( ( HFILE ) theFile, 0L, FILE_CURRENT, &FilePos );
  328.     return( ( DosSetFileSize( ( HFILE ) theFile, FilePos ) == NO_ERROR ) ? OK : IO_ERROR );
  329. #else
  330.     DosChgFilePtr( ( HFILE ) theFile, 0L, FILE_CURRENT, &FilePos );
  331.     return( ( DosNewSize( ( HFILE ) theFile, FilePos )  == NO_ERROR ) ? OK : IO_ERROR );
  332. #endif
  333.     }
  334.  
  335. /****************************************************************************
  336. *                                                                            *
  337. *                            SYSTEM Functions                                *
  338. *                                                                            *
  339. *****************************************************************************
  340.  
  341. /* Which of the three file dates to set */
  342.  
  343. typedef enum { LASTWRITE, LASTACCESS, CREATION } TIMES;
  344.  
  345. /* Local function to set one of the timestamps of a file (or directory) */
  346.  
  347. static void setOneOfFileTimes( const char *fileName, const LONG Time,
  348.                                const TIMES TimeToSet )
  349.     {
  350.     FILESTATUS info;
  351.     FDATE date;
  352.     FTIME time;
  353.     struct tm *tmtime;
  354.  
  355.     tmtime = localtime( ( time_t * ) &Time );
  356.  
  357.     time.twosecs = tmtime->tm_sec / 2;
  358.     time.minutes = tmtime->tm_min;
  359.     time.hours = tmtime->tm_hour ;
  360.     date.day = tmtime->tm_mday;
  361.     date.month = tmtime->tm_mon + 1;
  362.     date.year = tmtime->tm_year - 80;
  363.  
  364.     /* Get information for file */
  365. #ifdef OS2_32
  366.     DosQueryPathInfo( ( PSZ ) fileName, FIL_STANDARD, &info, sizeof( info ) );
  367. #else
  368.     DosQPathInfo( ( PSZ ) fileName, FIL_STANDARD, ( PBYTE ) &info, \
  369.                   sizeof( info ), 0L );
  370. #endif /* OS2_32 */
  371.  
  372.     switch( TimeToSet )
  373.         {
  374.         case LASTWRITE:
  375.             info.fdateLastWrite = date;
  376.             info.ftimeLastWrite = time;
  377.             break;
  378.  
  379.         case LASTACCESS:
  380.             info.fdateLastAccess = date;
  381.             info.ftimeLastAccess = time;
  382.             break;
  383.  
  384.         case CREATION:
  385.             info.fdateCreation = date;
  386.             info.ftimeCreation = time;
  387.             break;
  388.         }
  389.         /* The default is not to change the data */
  390.  
  391. #ifdef OS2_32
  392.     DosSetPathInfo( ( PSZ ) fileName, FIL_STANDARD, &info, \
  393.                     sizeof( info ), 0 );
  394. #else
  395.     DosSetPathInfo( ( PSZ ) fileName, FIL_STANDARD,( PBYTE) &info, \
  396.                     sizeof( info ), 0, 0L );
  397. #endif /* OS2_32 */
  398.     }
  399.  
  400. /* Set a files (or directories) timestamp */
  401.  
  402. void setFileTime( const char *fileName, const LONG fileTime )
  403.     {
  404.     setOneOfFileTimes( fileName, fileTime, LASTWRITE );
  405.     }
  406.  
  407. /* Set various other file timestamps */
  408.  
  409. void setAccessTime( const char *fileName, const LONG accessTime )
  410.     {
  411.     setOneOfFileTimes( fileName, accessTime, LASTACCESS );
  412.     }
  413.  
  414. void setCreationTime( const char *fileName, const LONG creationTime )
  415.     {
  416.     setOneOfFileTimes( fileName, creationTime, CREATION );
  417.     }
  418.  
  419. int getCountry( void )
  420.     {
  421.     COUNTRYCODE CountCode;
  422.     COUNTRYINFO CountInfo;
  423. #ifdef OS2_32
  424.     ULONG retLen;
  425. #else
  426.     USHORT retLen;
  427. #endif /* OS2_32 */
  428.     USHORT result;
  429.  
  430.     /* Clear country and codepage */
  431.     CountCode.country = 0;
  432.     CountCode.codepage = 0;
  433.  
  434.     /* Try and get country info, defaulting to US if we can't find anything */
  435. #ifdef OS2_32
  436.     return( ( DosQueryCtryInfo( sizeof( CountInfo ), &CountCode, &CountInfo, \
  437.                                 &retLen ) != NO_ERROR ) ? \
  438.             0 : CountInfo.fsDateFmt );
  439. #else
  440.     return( ( DosGetCtryInfo( ( USHORT ) sizeof( CountInfo ), &CountCode, \
  441.                               &CountInfo, &retLen ) != NO_ERROR ) ? \
  442.             0 : CountInfo.fsDateFmt );
  443. #endif /* OS2_32 */
  444.     }
  445.  
  446. /* Find the first/next file in a directory.  When we do the findFirst() we
  447.    enquire about any EA's attached to the file/directory for later
  448.    processing */
  449.  
  450. time_t TimetoLong( FDATE FDate, FTIME FTime )
  451.     {
  452.     struct tm timeBuf;
  453.  
  454.     timeBuf.tm_sec = FTime.twosecs * 2;
  455.     timeBuf.tm_min = FTime.minutes;
  456.     timeBuf.tm_hour = FTime.hours;
  457.     timeBuf.tm_mday = FDate.day;
  458.     if( FDate.month > 0 )
  459.         /* Month range is from 1-12 */
  460.         timeBuf.tm_mon = FDate.month - 1;
  461.     else
  462.         /* Clear date if no access or creation time */
  463.         timeBuf.tm_mon = 0;
  464.     timeBuf.tm_year = FDate.year + 80;    /* Years since 1980 */
  465.     timeBuf.tm_isdst = -1;                /* Daylight saving indeterminate */
  466.     timeBuf.tm_wday = 0;
  467.     timeBuf.tm_yday = 0;
  468.  
  469.     return( mktime( &timeBuf ) );
  470.     }
  471.  
  472. BOOLEAN findFirst( const char *filePath, const ATTR fileAttr, FILEINFO *fileInfo )
  473.     {
  474. #ifdef OS2_32
  475.     FILEFINDBUF4 FindBuffer;
  476.     ULONG FindCount = 1;
  477. #else
  478.     FILEFINDBUF2 FindBuffer;
  479.     USHORT FindCount = 1;
  480. #endif /* OS2_32 */
  481.     HDIR FindHandle = HDIR_CREATE;    /* OS allocates new file handle */
  482.  
  483. #ifdef OS2_32
  484.     if( DosFindFirst( ( PSZ ) filePath, &FindHandle, fileAttr, \
  485.                       &FindBuffer, sizeof( FindBuffer ), &FindCount, \
  486.                       FIL_QUERYEASIZE ) != NO_ERROR )
  487. #else
  488.     if( DosFindFirst2( ( PSZ ) filePath, &FindHandle, fileAttr, \
  489.                        &FindBuffer, sizeof( FindBuffer ), &FindCount, \
  490.                        FIL_QUERYEASIZE, 0L ) )
  491. #endif /* OS2_32 */
  492.         return( FALSE );
  493.  
  494.     fileInfo->hdir = FindHandle;
  495.     strncpy( fileInfo->fName, FindBuffer.achName, FindBuffer.cchName );
  496.     fileInfo->fName[ FindBuffer.cchName ] = '\0';
  497.     fileInfo->fSize = FindBuffer.cbFile;
  498.     fileInfo->fAttr = FindBuffer.attrFile;
  499.     fileInfo->eaSize = FindBuffer.cbList;
  500.     fileInfo->fTime = TimetoLong( FindBuffer.fdateLastWrite, \
  501.                                   FindBuffer.ftimeLastWrite );
  502.     fileInfo->cTime = TimetoLong( FindBuffer.fdateCreation, \
  503.                                   FindBuffer.ftimeCreation );
  504.     fileInfo->aTime = TimetoLong( FindBuffer.fdateLastAccess, \
  505.                                   FindBuffer.ftimeLastAccess );
  506.     return TRUE;
  507.     }
  508.  
  509. BOOLEAN findNext( FILEINFO *fileInfo )
  510.     {
  511. #ifdef OS2_32
  512.     FILEFINDBUF4 FindBuffer;
  513.     ULONG FileCount = 1;
  514. #else
  515.     FILEFINDBUF2 FindBuffer;
  516.     USHORT FileCount = 1;
  517. #endif /* OS2_32 */
  518.  
  519.     if( DosFindNext( fileInfo->hdir, ( PFILEFINDBUF ) &FindBuffer,
  520.                      sizeof( FindBuffer ), &FileCount ) != NO_ERROR )
  521.         return( FALSE );
  522.  
  523.     strncpy( fileInfo->fName, FindBuffer.achName, FindBuffer.cchName );
  524.     fileInfo->fName[ FindBuffer.cchName ] = '\0';
  525.     fileInfo->fSize = FindBuffer.cbFile;
  526.     fileInfo->fAttr = FindBuffer.attrFile;
  527.     fileInfo->eaSize = FindBuffer.cbList;
  528.     fileInfo->fTime = TimetoLong( FindBuffer.fdateLastWrite, \
  529.                                   FindBuffer.ftimeLastWrite );
  530.     fileInfo->cTime = TimetoLong( FindBuffer.fdateCreation, \
  531.                                   FindBuffer.ftimeCreation );
  532.     fileInfo->aTime = TimetoLong( FindBuffer.fdateLastAccess, \
  533.                                   FindBuffer.ftimeLastAccess );
  534.     return TRUE;
  535.     }
  536.  
  537. void findEnd( FILEINFO *fileInfo )
  538.     {
  539.     DosFindClose( ( HDIR ) fileInfo->hdir );
  540.     }
  541.  
  542. /* Check whether two pathnames refer to the same file */
  543.  
  544. BOOLEAN isSameFile( const char *pathName1, const char *pathName2 )
  545.     {
  546.     char InfoBuf1[ MAX_PATH ], InfoBuf2[ MAX_PATH ];
  547.     USHORT cbInfoBuf = MAX_PATH;
  548.  
  549.     /* Get the qualified filenames for the two paths */
  550. #ifdef OS2_32
  551.     DosQueryPathInfo( ( PSZ ) pathName1, FIL_QUERYFULLNAME, \
  552.                       &InfoBuf1, MAX_PATH );
  553.     DosQueryPathInfo( ( PSZ ) pathName2, FIL_QUERYFULLNAME, \
  554.                       &InfoBuf2, MAX_PATH );
  555. #else
  556.     DosQPathInfo( ( PSZ ) pathName1, FIL_QUERYFULLNAME, \
  557.                   ( PBYTE ) &InfoBuf1, cbInfoBuf, 0 );
  558.     DosQPathInfo( ( PSZ ) pathName2, FIL_QUERYFULLNAME, \
  559.                   ( PBYTE ) &InfoBuf2, cbInfoBuf, 0 );
  560. #endif /* OS2_32 */
  561.  
  562.     return( matchString( InfoBuf1, InfoBuf2, NO_WILDCARDS ) );
  563.     }
  564.  
  565. void getScreenSize( void )
  566.     {
  567. #ifdef OS2_32
  568.     /* Unfortunately the GNU GCC/2 port cannot generated thunked calls to the
  569.        old 16-bit DLL's. If this code is recompiled with ICC or maybe BCC
  570.        then the 16-bit code can be used */
  571.     screenWidth = 80;
  572.     screenHeight = 25;
  573. #else
  574.     VIOMODEINFO ModeInfo;
  575.  
  576.     ModeInfo.cb = sizeof( ModeInfo );
  577.     VioGetMode( &ModeInfo, 0 );
  578.  
  579.     screenWidth = ModeInfo.col;
  580.     screenHeight = ModeInfo.row;
  581. #endif /* OS2_32 */
  582.     }
  583.  
  584. /****************************************************************************
  585. *                                                                            *
  586. *                    Extended-Attribute Handling Functions                    *
  587. *                                                                            *
  588. ****************************************************************************/
  589.  
  590. #include "error.h"
  591. #include "tags.h"
  592.  
  593. /* The EA's used by HPACK archives */
  594.  
  595. BYTE EA_HPACK_ARCH_TYPE[] = "Hpack Archive";
  596. BYTE EA_HPACK_ICON[] = { 0x00, 0x00, 0x00, 0x00 };        /* Not yet defined */
  597. BYTE EA_HPACK_ASSOCTBL[] = { 0x00, 0x00, 0x00, 0x00 };    /* Not yet defined */
  598.  
  599. /* Names for various EA types */
  600.  
  601. #define OS2_MISC    LONG_TAG( TAG_OS2_MISC_EA )
  602.  
  603. #define ICON_NAME        ".ICON"
  604. #define LONGNAME_NAME    ".LONGNAME"
  605.  
  606. #ifndef OS2_32
  607.  
  608. /* Variables and data structures used for handling EA's, these are
  609.    defined in the 32 BIT API, so these will be included in os2.h */
  610.  
  611. typedef struct _FEA2         /* fea2 */
  612.         {
  613. #ifdef __32BIT__                    /* This redundant for now, but keep it here
  614.                                        just in case */
  615.         ULONG oNextEntryOffset;        /* New field */
  616. #endif
  617.         BYTE fEA;
  618.         BYTE cbName;
  619.         USHORT cbValue;
  620.         CHAR szName[1];                /* New field */
  621.         } FEA2;
  622. typedef FEA2 *PFEA2;
  623.  
  624. typedef struct _FEA2LIST        /* fea2l */
  625.         {
  626.         ULONG cbList;
  627.         FEA2 list[ 1 ];
  628.         } FEA2LIST;
  629.  
  630. typedef FEA2LIST *PFEA2LIST;
  631.  
  632. typedef struct _GEA2            /* gea2 */
  633.         {
  634. #ifdef OS2_32
  635.         /* New field - redundant for now, but keep it here just in case */
  636.         ULONG oNextEntryOffset;
  637. #endif /* OS2_32 */
  638.         BYTE cbName;
  639.         CHAR szName[ 1 ];        /* New field */
  640.         } GEA2;
  641.  
  642. typedef GEA2 *PGEA2;
  643.  
  644. typedef struct _GEA2LIST        /* gea2l */
  645.         {
  646.         ULONG cbList;
  647.         GEA2 list[ 1 ];
  648.         } GEA2LIST;
  649.  
  650. typedef GEA2LIST *PGEA2LIST;
  651.  
  652. typedef struct _EAOP2            /* eaop2 */
  653.         {
  654.         PGEA2LIST fpGEA2List;    /* GEA set */
  655.         PFEA2LIST fpFEA2List;    /* FEA set */
  656.         ULONG oError;            /* Offset of FEA error */
  657.         } EAOP2;
  658.  
  659. typedef EAOP2 *PEAOP2;
  660.  
  661. typedef PVOID *PPVOID;
  662.  
  663. #define DSPI_WRTTHRU    0x10    /* Write through */
  664.  
  665. #endif /* OS2_32 */
  666.  
  667. /* The HoldFEA is used to hold individual EAs.  The member names correspond
  668.    directly to those of the FEA structure.  Note however, that both szName
  669.    and aValue are pointers to the values.  An additional field, next, is
  670.    used to link the HoldFEA's together to form a linked list. */
  671.  
  672. struct _HoldFEA
  673.     {
  674. #ifdef OS2_32
  675.     ULONG   oNextEntryOffset;    /* Not used in 16 bit code */
  676. #endif /* OS2_32 */
  677.     BYTE fEA;                    /* Flag byte */
  678.     BYTE cbName;
  679.     USHORT cbValue;
  680.     CHAR *szName;
  681.     BYTE *aValue;
  682.     struct _HoldFEA *next;
  683.     };
  684.  
  685. typedef struct _HoldFEA HOLDFEA;
  686.  
  687. #define MAX_GEA                500L /* Max size for a GEA List */
  688. #define REF_ASCIIZ            1    /* Reference type for DosEnumAttribute */
  689.  
  690. #define GET_INFO_LEVEL1        1    /* Get info from SFT */
  691. #define GET_INFO_LEVEL2        2    /* Get size of FEAlist */
  692. #define GET_INFO_LEVEL3        3    /* Get FEAlist given the GEAlist */
  693. #define GET_INFO_LEVEL4        4    /* Get whole FEAlist */
  694. #define GET_INFO_LEVEL5        5    /* Get FSDname */
  695.  
  696. #define SET_INFO_LEVEL1        1    /* Set info in SFT */
  697. #define SET_INFO_LEVEL2        2    /* Set FEAlist */
  698.  
  699. typedef enum { STORE_WHOLE_EA, STORE_EA_VALUE } TAG_TYPE;
  700.  
  701. /* Free_FEAList (pFEA)
  702.    Frees the memory used by the linked list of HOLDFEA's pointed to by pFEA */
  703.  
  704. VOID Free_FEAList( HOLDFEA *pFEA )
  705.     {
  706.     HOLDFEA *next;    /* Holds the next field since we free the structure
  707.                        before reading the current next field */
  708.  
  709.     /* Step through the list freeing all the fields */
  710.     while( pFEA )
  711.         {
  712.         /* Free the fields of the struct */
  713.         next = pFEA->next;
  714.         if( pFEA->szName != NULL )
  715.             /* Free if non-NULL name */
  716.             hfree(pFEA->szName);
  717.         if( pFEA->aValue != NULL )
  718.             /* Free if non-NULL value */
  719.             hfree(pFEA->aValue);
  720.  
  721.         /* Free the pFEA struct itself and move on to the next field */
  722.         hfree(pFEA);
  723.         pFEA = next;
  724.         }
  725.     }
  726.  
  727. /* Read the EA type, this is stored at the start of the EA value */
  728.  
  729. ULONG getEAType( const CHAR *Value )
  730.     {
  731.     USHORT Type = *( USHORT * ) Value;
  732.  
  733.     return( Type );
  734.     }
  735.  
  736. /* Return the EA length, stored in pFEA, this done so that it is calculated
  737.    in only one place */
  738.  
  739. ULONG getEALength( const HOLDFEA *pFEA )
  740.     {
  741.     return( sizeof( FEA2 )
  742.             - sizeof( CHAR )    /* Don't include the first element of aValue */
  743.             + pFEA->cbName + 1    /* Length of ASCIIZ name */
  744.             + pFEA->cbValue );    /* The value length */
  745.     }
  746.  
  747. /* Set the first two words of the EA value, this is usually the
  748.    EA type and EA size in pFEA, from the values Type and Size */
  749.  
  750. void setEATypeSize( const HOLDFEA *pFEA, const USHORT Type, const USHORT Size )
  751.     {
  752.     USHORT *valPtr = ( USHORT * ) pFEA->aValue;
  753.     valPtr[ 0 ] = Type;
  754.     valPtr[ 1 ] = Size;
  755.     }
  756.  
  757. /* Read the first two words of the EA value, this is usually the
  758.    EA type and EA size in pFEA, into the Type and Size */
  759.  
  760. void getEATypeSize( const HOLDFEA *pFEA, USHORT *Type, USHORT *Size )
  761.     {
  762.     USHORT *valPtr = ( USHORT * ) pFEA->aValue;
  763.     *Type = valPtr[ 0 ];
  764.     *Size = valPtr[ 1 ];
  765.     }
  766.  
  767. /* Get the address of the EA value in pFEA, ie skip over the Type and Size */
  768.  
  769. VOID* getEADataVal (const HOLDFEA *pFEA)
  770.     {
  771.     /* Skip over the type and size */
  772.     return pFEA->aValue + 2 * sizeof ( USHORT );
  773.     }
  774.  
  775. /* QueryEAs (szFileName)
  776.       find all EAs that file szFileName has
  777.       return these in the linked list of HOLDFEAs
  778.       if no EAs exist or the linked list cannot be created then
  779.       return NULL
  780.   This function is modelled after code from IBM's Toolkit */
  781.  
  782. HOLDFEA *QueryEAs( const CHAR *szFileName )
  783.     {
  784.     HOLDFEA *pHoldFEA;        /* The start of the linked list */
  785.  
  786.     CHAR *pAllocc = NULL;    /* Temp buffer used with DosEnumAttribute */
  787.     CHAR *pBigAlloc = NULL;    /* Temp buffer to hold each EA as it is read in */
  788.     USHORT cbBigAlloc = 0;
  789.  
  790.     ULONG ulEntryNum = 1;    /* Count of current EA to read (1-relative) */
  791.     ULONG ulEnumCnt;        /* Number of EAs for Enum to return, always 1 */
  792.  
  793.     HOLDFEA *pLastIn = 0;    /* Points to last EA added, so new EA can link    */
  794.     HOLDFEA *pNewFEA = NULL; /* Struct to build the new EA in                  */
  795.  
  796.     FEA2 *pFEA;                /* Used to read from Enum's return buffer */
  797.     GEA2LIST *pGEAList;        /* Ptr used to set up buffer for DosQueryPathInfo() */
  798.     EAOP2 eaopGet;            /* Used to call DosQueryPathInfo() */
  799.  
  800.     pAllocc = hmalloc( MAX_GEA );    /* Allocate room for a GEA list */
  801.     pFEA = ( FEA2 * ) pAllocc;
  802.     pHoldFEA = NULL;        /* Initialize the linked list */
  803.  
  804.     /* Loop through all the EA's adding them to the list */
  805.     while( TRUE )
  806.         {
  807.         ulEnumCnt = 1;        /* No of EAs to retrieve */
  808.         if( DosEnumAttribute( REF_ASCIIZ,    /* Read into EA name into */
  809.                               szFileName,    /* pAlloc Buffer */
  810.                               ulEntryNum, pAllocc, MAX_GEA, &ulEnumCnt,
  811. #ifndef OS2_32                /* 16 bit API has an extra parameter */
  812.                               ( LONG ) GET_INFO_LEVEL1, 0 ) )
  813. #else
  814.                               ( LONG ) GET_INFO_LEVEL1 ) )
  815. #endif /* OS2_32 */
  816.             break;    /* An error */
  817.  
  818.         /* Exit if all the EA's have been read */
  819.         if( ulEnumCnt != 1 )
  820.             break;
  821.  
  822.         /* Move on to next EA */
  823.         ulEntryNum++;
  824.  
  825.         /* Try and allocate the HoldFEA structure */
  826.         if( ( pNewFEA = hmalloc( sizeof( HOLDFEA ) ) ) == NULL )
  827.             {
  828.             hfree( pAllocc );
  829.             Free_FEAList( pHoldFEA );
  830.             return( NULL );
  831.             }
  832.  
  833.         /* Fill in the HoldFEA structure */
  834.         pNewFEA->cbName = pFEA->cbName;
  835.         pNewFEA->cbValue= pFEA->cbValue;
  836.         pNewFEA->fEA = pFEA->fEA;
  837.         pNewFEA->next = '\0';
  838.  
  839.         /* Allocate the two arrays */
  840.         if( ( pNewFEA->szName = hmalloc( pFEA->cbName + 1 ) ) == NULL || \
  841.             ( pNewFEA->aValue = hmalloc( pFEA->cbValue ) ) == NULL )
  842.             {
  843.             /* Out of memory, clean up and exit */
  844.             if( pNewFEA->szName )
  845.                 hfree( pNewFEA->szName );
  846.             if( pNewFEA->aValue )
  847.                 hfree( pNewFEA->aValue );
  848.  
  849.             hfree( pAllocc );
  850.             hfree( pNewFEA );
  851.  
  852.             Free_FEAList( pHoldFEA );
  853.             return( NULL );
  854.             }
  855.  
  856.         /* Copy EA name across */
  857.         strcpy( pNewFEA->szName, pFEA->szName );
  858.         cbBigAlloc = sizeof( FEA2LIST ) + pNewFEA->cbName + 1 + pNewFEA->cbValue;
  859.                             /* +1 is for '\0' */
  860.         if( ( pBigAlloc = hmalloc( cbBigAlloc ) ) == NULL )
  861.             {
  862.             hfree( pNewFEA->szName );
  863.             hfree( pNewFEA->aValue );
  864.             hfree( pAllocc );
  865.             hfree( pNewFEA );
  866.             Free_FEAList( pHoldFEA );
  867.             return( NULL );
  868.             }
  869.  
  870.         /* Set up GEAlist structure */
  871.         pGEAList = ( GEA2LIST * ) pAllocc;
  872.         pGEAList->cbList = sizeof( GEA2LIST ) + pNewFEA->cbName;    /* + 1 for NULL */
  873. #ifdef OS2_32
  874.         pGEAList->list[ 0 ].oNextEntryOffset = 0L;
  875. #endif /* OS2_32 */
  876.         pGEAList->list[ 0 ].cbName = pNewFEA->cbName;
  877.         strcpy( pGEAList->list[ 0 ].szName, pNewFEA->szName );
  878.  
  879.         eaopGet.fpGEA2List = ( GEA2LIST FAR * ) pAllocc;
  880.         eaopGet.fpFEA2List = ( FEA2LIST FAR * ) pBigAlloc;
  881.  
  882.         eaopGet.fpFEA2List->cbList = cbBigAlloc;
  883.  
  884.         /* Get the complete EA info and copy the EA value */
  885. #ifndef OS2_32                /* The 16 bit API has an extra parameter */
  886.         DosQPathInfo( szFileName, FIL_QUERYEASFROMLIST, ( PVOID ) &eaopGet, \
  887.                       sizeof( EAOP2 ), 0 );
  888. #else
  889.         DosQueryPathInfo( szFileName, FIL_QUERYEASFROMLIST, ( PVOID ) &eaopGet, \
  890.                           sizeof( EAOP2 ) );
  891. #endif /* OS2_32 */
  892.         memcpy( pNewFEA->aValue, \
  893.                 pBigAlloc + sizeof( FEA2LIST ) + pNewFEA->cbName, \
  894.                 pNewFEA->cbValue );
  895.  
  896.         /* Release the temp. Enum buffer */
  897.         hfree( pBigAlloc );
  898.  
  899.         /* Add to the list */
  900.         if( pHoldFEA == NULL )
  901.             pHoldFEA = pNewFEA;
  902.         else
  903.             pLastIn->next = pNewFEA;
  904.         pLastIn = pNewFEA;
  905.         }
  906.  
  907.     /* Free up the GEA buffer for DosEnum() */
  908.     hfree( pAllocc );
  909.  
  910.     return pHoldFEA;
  911.     }
  912.  
  913.  
  914. /* WriteEAs(szFileName, pHoldFEA)
  915.  
  916.    Write the EAs contained in the linked list pointed to by pHoldFEA
  917.    to the file szFileName.
  918.  
  919.    Returns TRUE if the write was successful, FALSE otherwise */
  920.  
  921. BOOLEAN WriteEAs( const char *szFileName, HOLDFEA *pHoldFEA )
  922.     {
  923.     HOLDFEA *pHFEA = pHoldFEA;
  924.     EAOP2 eaopWrite;
  925.     CHAR *aPtr = NULL;
  926.     USHORT usMemNeeded, usRet;
  927.  
  928.     eaopWrite.fpGEA2List = NULL;
  929.     while( pHFEA )                                  /* Go through each HoldFEA */
  930.         {
  931. #ifndef OS2_32                /* The 16 bit API doesn't use the name */
  932.         usMemNeeded = sizeof( FEA2LIST ) - \
  933.                       sizeof( eaopWrite.fpFEA2List->list[0].szName ) + \
  934.                       pHFEA->cbName + 1 + pHFEA->cbValue;
  935. #else
  936.         usMemNeeded = sizeof( FEA2LIST ) + pHFEA->cbName + 1 + pHFEA->cbValue;
  937. #endif
  938.         if( ( aPtr = hmalloc( usMemNeeded ) ) == NULL )
  939.             return FALSE;
  940.  
  941.         /* Fill in eaop structure */
  942.         eaopWrite.fpFEA2List = ( FEA2LIST FAR * ) aPtr;
  943.         eaopWrite.fpFEA2List->cbList = usMemNeeded;
  944. #ifdef OS2_32
  945.         eaopWrite.fpFEA2List->list[ 0 ].oNextEntryOffset = pHFEA->oNextEntryOffset;
  946. #endif /* OS2_32 */
  947.         eaopWrite.fpFEA2List->list[ 0 ].fEA = pHFEA->fEA;
  948.         eaopWrite.fpFEA2List->list[ 0 ].cbName = pHFEA->cbName;
  949.         eaopWrite.fpFEA2List->list[ 0 ].cbValue = pHFEA->cbValue;
  950.         strcpy( eaopWrite.fpFEA2List->list[ 0 ].szName, pHFEA->szName );
  951.         memcpy( eaopWrite.fpFEA2List->list[ 0 ].szName + pHFEA->cbName + 1, \
  952.                 pHFEA->aValue, pHFEA->cbValue );
  953.  
  954.         /* Write out the EA */
  955.         usRet = DosSetPathInfo( szFileName, FIL_QUERYEASIZE,
  956.                                 ( PVOID ) &eaopWrite, sizeof( EAOP2 ),
  957. #ifndef OS2_32                /* The 16 bit API has an extra parameter */
  958.                                 DSPI_WRTTHRU, 0 );
  959. #else
  960.                                 DSPI_WRTTHRU );
  961. #endif
  962.         /* Free up the FEALIST struct */
  963.         hfree( aPtr );
  964.  
  965.         /* If the write failed, leave now */
  966.         if( usRet )
  967.             return FALSE;
  968.  
  969.         pHFEA = pHFEA->next;
  970.         }
  971.  
  972.     return( TRUE );
  973.     }
  974.  
  975. /* Copy EA's from a file to an archive in HPACK tagged form.
  976.    Either the whole EA will be stored (flag, name len, data len, name, ...)
  977.    or just the EA value (the rest can be reconstructed from the HPACK tag.
  978.  
  979.    The current EA tags are ICON, LONGNAME (both just store the value)
  980.    and MISC (store the whole EA).
  981.  
  982.    MISC is a superset of the other EA types, and all EA's can in fact be
  983.    stored as a MISC tag, however this is less efficient and portable */
  984.  
  985. LONG storeEAinfo( const BOOLEAN isFile, const char *pathName, const LONG eaSize1, const FD outFD )
  986.     {
  987.     HOLDFEA *pHoldFEA;            /* Global EA linked-list pointer */
  988.     HOLDFEA *pFEA;
  989.     WORD eaLength = ERROR;
  990.     WORD tagLength;
  991.     WORD i, dataLength = 0;
  992.     TAG_TYPE tagType = STORE_WHOLE_EA;
  993.     WORD theTag;
  994.     USHORT eaType, Size;
  995.     BOOLEAN isDir = !isFile;
  996.     BYTE *dataPtr;
  997.  
  998.     /* Check whether there are any EA's to store */
  999.     if( !( pHoldFEA = QueryEAs( pathName ) ) )
  1000.         return (0);
  1001.  
  1002.     /* Loop through each EA found, using a temporary pointer */
  1003.     pFEA = pHoldFEA;
  1004.     while( pFEA != NULL )
  1005.         {
  1006.         /* Determine EA type and write appropriate tag info */
  1007.         switch( getEAType ( pFEA->aValue ) )
  1008.             {
  1009.             case EAT_ASCII:
  1010.                 /* Length-preceded ASCII.  Check whether the EA can be
  1011.                    recovered from the tag type */
  1012.                 if( !strncmp( pFEA->szName, ".LONGNAME", pFEA->cbName ) && \
  1013.                     ( pFEA->fEA == 0 ) )
  1014.                     {
  1015.                     tagType = STORE_EA_VALUE;
  1016.                     theTag = TAG_LONGNAME;
  1017.                     }
  1018.                 else
  1019.                     tagType = STORE_WHOLE_EA;
  1020.                 break;
  1021.  
  1022.             case EAT_ICON:
  1023.                 /* Length-preceded icon.  Check whether the EA can be
  1024.                    recovered from the tag type */
  1025.                 if( !strncmp( pFEA->szName, ".ICON", pFEA->cbName ) && \
  1026.                     ( pFEA->fEA == 0 ) )
  1027.                     {
  1028.                     tagType = STORE_EA_VALUE;
  1029.                     theTag = TAG_OS2_ICON;
  1030.                     }
  1031.                 else
  1032.                     tagType = STORE_WHOLE_EA;
  1033.                 break;
  1034.  
  1035.             default:
  1036.                 tagType = STORE_WHOLE_EA;
  1037.                 break;
  1038.             }
  1039.  
  1040.  
  1041.         /* Store type of EA as a tag */
  1042.         switch( tagType )
  1043.             {
  1044.             case STORE_EA_VALUE:
  1045.                 /* Just store the EA value, the other fields
  1046.                    are implicit in the tag */
  1047.                 eaLength = pFEA->cbValue;
  1048.                 eaLength -= 2 * sizeof( USHORT );    /* EA_VALUE.type & .eaSize are not stored */
  1049.                 tagLength = eaLength + sizeof( WORD );    /* For CRC check */
  1050.  
  1051.                 /* Write the tag as either a normal file or a directory tag */
  1052.                 if( isDir )
  1053.                     {
  1054.                     dataLength += addDirData( theTag, TAGFORMAT_STORED, tagLength, LEN_NONE );
  1055.                     checksumDirBegin( RESET_CHECKSUM );
  1056.                     }
  1057.                 else
  1058.                     {
  1059.                     dataLength += writeTag( theTag, TAGFORMAT_STORED, tagLength, LEN_NONE );
  1060.                     checksumBegin( RESET_CHECKSUM );
  1061.                     }
  1062.  
  1063.                 dataLength += tagLength ;
  1064.                 break;
  1065.  
  1066.             case STORE_WHOLE_EA:
  1067.                 /* Store the whole EA */
  1068.  
  1069. #ifndef OS2_32
  1070.                 eaLength = getEALength( pFEA ) - sizeof( CHAR );
  1071.                         /* Don't store the null in the Name */
  1072. #else
  1073.                 eaLength = getEALength( pFEA ) - sizeof( pFEA->oNextEntryOffset ) - sizeof( CHAR );
  1074.                         /* Don't store the offset or the null in the Name */
  1075. #endif /* OS2_32 */
  1076.                 tagLength = eaLength + sizeof( WORD );    /* For CRC check */
  1077.  
  1078.                 /* Write the tag as either a normal file or a directory tag */
  1079.                 if( isDir )
  1080.                     {
  1081.                     dataLength += addDirData( TAG_OS2_MISC_EA, TAGFORMAT_STORED, tagLength, LEN_NONE );
  1082.                     checksumDirBegin( RESET_CHECKSUM );
  1083.                     }
  1084.                 else
  1085.                     {
  1086.                     dataLength += writeTag( TAG_OS2_MISC_EA, TAGFORMAT_STORED, tagLength, LEN_NONE );
  1087.                     checksumBegin( RESET_CHECKSUM );
  1088.                     }
  1089.  
  1090.                 /* Write the flag, name, etc */
  1091.                 getEATypeSize( pFEA, &eaType, &Size );
  1092.                 if( isDir )
  1093.                     {
  1094.                     fputDirByte( pFEA->fEA );
  1095. /*                    fputDirByte( pFEA->cbName ); */
  1096.                     fputDirWord( pFEA->cbValue );
  1097.                     for( i = 0; i < pFEA->cbName; i++ )
  1098.                         fputDirByte( pFEA->szName[ i ] );
  1099.                     fputDirByte( '\0' );
  1100.                     fputDirWord( eaType );
  1101.                     fputDirWord( Size );
  1102.                     }
  1103.                 else
  1104.                     {
  1105.                     fputByte( pFEA->fEA );
  1106. /*                    fputByte( pFEA->cbName ); */
  1107.                     fputWord( pFEA->cbValue );
  1108.                     for( i = 0; i < pFEA->cbName; i++ )
  1109.                         fputByte( pFEA->szName[ i ] );
  1110.                     fputByte( '\0' );
  1111.                     fputWord( eaType );
  1112.                     fputWord( Size );
  1113.                     }
  1114.  
  1115.                 dataLength += tagLength;
  1116.  
  1117.                 /* Adjust eaLength for the data already written */
  1118.                 eaLength = pFEA->cbValue - 2 * sizeof( USHORT );
  1119.                             /* Don't include type & size */
  1120.                 break;
  1121.             }
  1122.  
  1123.         dataPtr = getEADataVal( pFEA );        /* Where data starts */
  1124.  
  1125.         /* Copy EA data to outFD */
  1126.  
  1127. /* Try and compress the buffer before we write it - not implemented yet */
  1128.         if( isDir )
  1129.             while( eaLength-- )
  1130.                 fputDirByte( *dataPtr++ );
  1131.         else
  1132.             while( eaLength-- )
  1133.                 fputByte( *dataPtr++ );
  1134.  
  1135.         /* Write CRC for data */
  1136.         if( isDir )
  1137.             {
  1138.             checksumDirEnd();
  1139.             fputDirWord( crc16 );
  1140.             }
  1141.         else
  1142.             {
  1143.             checksumEnd();
  1144.             fputWord( crc16 );
  1145.             }
  1146.  
  1147.         /* Go to next EA */
  1148.         pFEA = pFEA->next;
  1149.         }
  1150.  
  1151.     Free_FEAList( pFEA );
  1152.  
  1153.     return( dataLength );
  1154.     }
  1155.  
  1156. /* Set an EA from tagged EA info, see above for EA tag structure */
  1157.  
  1158. void setEAinfo( const char *filePath, const TAGINFO *tagInfo, const FD srcFD )
  1159.     {
  1160.     HOLDFEA *pFEA;
  1161.     char *dataPtr;
  1162.     WORD eaType, eaSize;
  1163.     int i, eaLen = ( int ) tagInfo->dataLength - sizeof( WORD );
  1164.             /* Subtract CRC check, Need this since length is const */
  1165.  
  1166.     /* Initialize HOLDFEA to receive EA's */
  1167.     if( ( pFEA = hmalloc( sizeof( HOLDFEA ) ) ) == NULL )
  1168.         {
  1169.         /* Skip over the tag before returning */
  1170.         skipSeek( tagInfo->dataLength );
  1171.         return;
  1172.         }
  1173.     pFEA->next = NULL;
  1174.  
  1175.     /* Read the header size and the EA flag, don't include checksum */
  1176.     checksumSetInput( tagInfo->dataLength - sizeof( WORD ), RESET_CHECKSUM );
  1177.  
  1178. /* eaName might have to be constructed locally, eg if all icons are called
  1179.    "ICON" there is little need to store this information, we can examine the
  1180.    tag type and set the name depending on this info.  Otherwise we read the
  1181.    name (0..255 chars, Pascal string) from srcFD into the EA buffer */
  1182.  
  1183.     switch( tagInfo->tagID )
  1184.         {
  1185.         case TAG_OS2_ICON:
  1186.             /* Construct EA */
  1187.             pFEA->cbName = sizeof( ICON_NAME ) - 1;
  1188.             if( ( pFEA->szName = hmalloc( pFEA->cbName ) ) == NULL )
  1189.                 {
  1190.                 /* Skip data before returning */
  1191.                 skipSeek( tagInfo->dataLength );
  1192.                 hfree( pFEA );
  1193.                 return;
  1194.                 }
  1195.             strcpy( pFEA->szName, ICON_NAME );
  1196.             pFEA->fEA = 0;
  1197.             pFEA->cbValue = eaLen + 2 * sizeof( USHORT );    /* Add type and length */
  1198.             eaType = EAT_ICON;
  1199.             eaSize = eaLen;
  1200.             eaLen = getEALength( pFEA );
  1201.             break;
  1202.  
  1203.         case TAG_LONGNAME:
  1204.             /* Construct EA */
  1205.             pFEA->cbName = sizeof( LONGNAME_NAME ) - 1;
  1206.             if( ( pFEA->szName = hmalloc( pFEA->cbName ) ) == NULL )
  1207.                 {
  1208.                 /* Skip data before returning */
  1209.                 skipSeek( tagInfo->dataLength );
  1210.                 hfree( pFEA );
  1211.                 return;
  1212.                 }
  1213.             strcpy( pFEA->szName, LONGNAME_NAME );
  1214.             pFEA->fEA = 0;
  1215.             pFEA->cbValue = eaLen + 2 * sizeof( USHORT );    /* Add type and length */
  1216.             eaType = EAT_ASCII;
  1217.             eaSize = eaLen;
  1218.             eaLen = getEALength( pFEA );
  1219.             break;
  1220.  
  1221.         case TAG_OS2_MISC_EA:
  1222.             /* Read flags, name etc from source file */
  1223.             pFEA->fEA = fgetByte();
  1224. /*            i = pFEA->cbName = fgetByte();
  1225.             if( ( pFEA->szName = hmalloc( pFEA->cbName + 1 ) ) == NULL )
  1226. */
  1227.             /* Allocate enough room for the name (can't be bigger that the tag) */
  1228.             if( ( pFEA->szName = hmalloc( tagInfo->dataLength - sizeof( WORD ) - sizeof( BYTE ) ) ) == NULL )
  1229.                 {
  1230.                 /* Again skip data */
  1231.                 skipSeek( tagInfo->dataLength - sizeof( BYTE ) - sizeof( BYTE ) );
  1232.                 hfree( pFEA );
  1233.                 return;
  1234.                 }
  1235.             pFEA->cbValue = fgetWord();
  1236.             dataPtr = pFEA->szName;
  1237. /*            while( i-- )
  1238.                 *dataPtr++ = fgetByte();
  1239.             pFEA->szName[ pFEA->cbName ] = '\0';
  1240. */
  1241.             i = 0;
  1242.             while( ( dataPtr[ i++ ] = fgetByte() ) );
  1243.             pFEA->cbName = i - 1;
  1244.  
  1245.             /* Read the type and size */
  1246.             eaType = fgetWord();
  1247.             eaSize = fgetWord();    /* Probably the size, but not for multi valued */
  1248.             eaLen = getEALength( pFEA );
  1249.         }
  1250.  
  1251.     if( ( pFEA->aValue = hmalloc( pFEA->cbValue ) ) == NULL )
  1252.         {
  1253.         /* Skip data */
  1254.         skipSeek( tagInfo->dataLength - \
  1255.                   ( pFEA->cbValue - 2 * sizeof( USHORT ) ) + \
  1256.                   sizeof( WORD ) );
  1257.         hfree( pFEA->szName );
  1258.         hfree( pFEA );
  1259.         return;
  1260.         }
  1261.  
  1262.     setEATypeSize( pFEA, eaType, eaSize );
  1263.  
  1264.     /* Construct data portion of EA */
  1265.     i = pFEA->cbValue - 2 * sizeof( USHORT );    /* Don't include the type or size */
  1266.     dataPtr = getEADataVal( pFEA );
  1267.  
  1268. /* We may need to decompress this.  Currently compression isn't supported.
  1269.    When it is, the uncompressed size is given by tagInfo->uncoprLen */
  1270.     while( i-- )
  1271.         *dataPtr++ = fgetByte();
  1272.  
  1273.     /* Make sure data was non-corrupted */
  1274.     if( fgetWord() == crc16 )
  1275.         /* Ignore errors on Writing for the moment */
  1276.         WriteEAs( filePath, pFEA );
  1277.  
  1278.     Free_FEAList( pFEA );
  1279.     }
  1280.  
  1281. /* Copy all EA's from one file to another */
  1282.  
  1283. void copyExtraInfo( const char *srcFilePath, const char *destFilePath )
  1284.     {
  1285.     HOLDFEA *pFEA;
  1286.  
  1287.     pFEA = QueryEAs( srcFilePath );
  1288.     WriteEAs( destFilePath, pFEA );
  1289.  
  1290.     Free_FEAList (pFEA);
  1291.     }
  1292.  
  1293. /* Set any necessary extra information associated with a file */
  1294.  
  1295. static void setEA( const char *filePath, const WORD type, const char *name, \
  1296.                    const BYTE *value, const WORD length )
  1297.     {
  1298.     HOLDFEA *pFEA;
  1299.     BYTE *dataPtr;
  1300.  
  1301.     /* Initialize HOLDFEA to receive EA's */
  1302.     if( ( pFEA = hmalloc( sizeof( HOLDFEA ) ) ) == NULL )
  1303.         return;
  1304.     pFEA->next = NULL;
  1305. #ifdef OS2_32
  1306.     pFEA->oNextEntryOffset = 0L;
  1307. #endif /* OS2_32 */
  1308.     pFEA->fEA = 0;
  1309.     pFEA->cbName = strlen ( name );
  1310.     pFEA->cbValue = length + 2 * sizeof( WORD );    /* Include type and size */
  1311.     if( ( pFEA->szName = hmalloc( pFEA->cbName ) ) == NULL )
  1312.         {
  1313.         hfree( pFEA );
  1314.         return;
  1315.         }
  1316.     strcpy( pFEA->szName, name);
  1317.     if( ( pFEA->aValue = hmalloc( pFEA->cbValue ) ) == NULL )
  1318.         {
  1319.         hfree( pFEA->szName );
  1320.         hfree( pFEA );
  1321.         return;
  1322.         }
  1323.  
  1324.     setEATypeSize( pFEA, type, length );
  1325.  
  1326.     dataPtr = getEADataVal( pFEA );
  1327.     memcpy( dataPtr, value, length );
  1328.  
  1329.     WriteEAs( filePath, pFEA );
  1330.     Free_FEAList( pFEA );
  1331.     }
  1332.  
  1333. void setExtraInfo( const char *filePath )
  1334.     {
  1335.     /* Attach the type, icon, and file creator information to the archive */
  1336.     setEA( filePath, EAT_ASCII, ".TYPE", EA_HPACK_ARCH_TYPE, \
  1337.            sizeof( EA_HPACK_ARCH_TYPE ) - 1 );
  1338. /*    putEA( theFD, ".ICON", EA_HPACK_ICON, \            */
  1339. /*           sizeof( EA_HPACK_ICON ), EAT_ICON );        */
  1340. /*    putEA( theFD, ".ASSOCTBL", EA_HPACK_ASSOCTBL, \    */
  1341. /*           sizeof( EA_HPACK_ASSOCTBL ), EAT_???? );    */
  1342.     }
  1343.  
  1344. /* Add a longname EA to a file or directory if it's been truncated on
  1345.    extraction */
  1346.  
  1347. void addLongName( const char *filePath, const char *longName )
  1348.     {
  1349.     FD theFD;
  1350.  
  1351.     if( ( theFD = hopen( filePath, O_RDONLY | S_DENYRDWR ) ) == ERROR )
  1352.         /* This should never happen since we've just created the file/dir */
  1353.         return;
  1354.  
  1355.     /* Save the non-truncated name as an EA */
  1356.     setEA( filePath, EAT_ASCII, ".LONGNAME", ( BYTE * ) longName, strlen( longName ) );
  1357.  
  1358.     hclose( theFD );
  1359.     }
  1360.  
  1361. #ifndef OS2_32
  1362.  
  1363. /* Determine the filesystem type.  The structure for the filesystem info
  1364.    seems to be:
  1365.  
  1366.     USHORT iType;                    \* Item type *\
  1367.     USHORT cbName;                    \* Length of item name, sans NULL *\
  1368.     UCHAR szName[];                    \* ASCIIZ item name *\
  1369.     NULL
  1370.     USHORT cbFSDName;                \* Length of FSD name, sans NULL *\
  1371.     UCHAR szFSDName[ 1 ];            \* ASCIIZ FSD name *\
  1372.     NULL
  1373.     USHORT cbFSAData;                \* Length of FSD Attach data returned *\
  1374.     UCHAR rgFSAData[ 60 ];            \* FSD Attach data from FSD *\
  1375.     NULL */
  1376.  
  1377. typedef struct {
  1378.                USHORT cbName;            /* Length of name, sans NULL */
  1379.                UCHAR szName[ 1 ];        /* ASCIIZ name */
  1380.                } FSNAME;
  1381.  
  1382. typedef struct {            /* Data structure for QFSAttach */
  1383.                USHORT iType;            /* Item type */
  1384.                FSNAME Name;                /* Item name */
  1385.                UCHAR rgFSAData[ 59 ];    /* Place to store data */
  1386.                } FSQINFO;
  1387.  
  1388. typedef FSQINFO FAR *PFSQINFO;
  1389.  
  1390. BOOLEAN queryFilesystemType( char *path )
  1391.     {
  1392.     USHORT nDrive;
  1393.     ULONG lMap;
  1394.     FSQINFO bData;
  1395.     BYTE bName[ 3 ];
  1396.     FSNAME *pFSName;
  1397.     USHORT cbData;
  1398.  
  1399.     /* Get drive */
  1400.     if( ( strlen( path ) > 0 ) && path[ 1 ] == ':' )
  1401.         bName[ 0 ] = path[ 0 ];
  1402.     else
  1403.         {
  1404.         DosQCurDisk( &nDrive, &lMap );
  1405.         bName[ 0 ] = ( char ) ( nDrive + '@' );
  1406.         }
  1407.     bName[ 1 ] = ':';
  1408.     bName[ 2 ] = 0;
  1409.  
  1410.     cbData = sizeof( bData );
  1411.  
  1412.     DosQFSAttach( ( PSZ ) bName, 0U, 1U, ( PBYTE ) &bData, &cbData, 0L );
  1413.     pFSName = &bData.Name;
  1414.     ( char * ) pFSName += pFSName->cbName + sizeof( pFSName->cbName ) + 1;
  1415.  
  1416.     return( strcmp ( ( char * ) &( pFSName->szName[ 0 ] ), "FAT" ) != 0 );
  1417.     }
  1418.  
  1419. #else
  1420.  
  1421. /* Determine the file system type. This uses a strange function that
  1422.    populates a variables sised buffer that YOU have to declare, not knowing
  1423.    how big to actually make it!  Plus to access the ASCIIZ strings you need
  1424.    to play games with the offsets to find the real potition of the data you
  1425.    are after */
  1426.  
  1427. #define FSQBUFFERSIZE    64
  1428.  
  1429. BOOLEAN queryFilesystemType( char *path )
  1430.     {
  1431.     ULONG nDrive;
  1432.     ULONG lMap;
  1433.     char buffer[ FSQBUFFERSIZE ];
  1434.     FSQBUFFER2 *bData = ( FSQBUFFER2 * ) buffer;
  1435.     char bName[ 3 ];
  1436.     ULONG bDataLen;
  1437.  
  1438.     if( ( strlen( path ) > 0 ) && path[ 1 ] == ':' )
  1439.         bName[ 0 ] = path[ 0 ];
  1440.     else
  1441.         {
  1442.         DosQueryCurrentDisk( &nDrive, &lMap );
  1443.         bName[ 0 ] = ( char ) ( nDrive + 'A' - 1 );
  1444.         }
  1445.  
  1446.     bName[ 1 ] = ':';
  1447.     bName[ 2 ] = 0;
  1448.  
  1449.     bDataLen = FSQBUFFERSIZE;
  1450.  
  1451.     DosQueryFSAttach( bName, 0, FSAIL_QUERYNAME, bData, &bDataLen );
  1452.     return( strcmp( bData->szFSDName + bData->cbName, "FAT" ) != 0 );
  1453.     }
  1454.  
  1455. #if defined( __gcc ) && !defined( __EMX__ )
  1456.  
  1457. /* NLS support for string case conversion */
  1458.  
  1459. static unsigned char cLCtbl[ 256 ], cUCtbl[ 256 ];
  1460. static BOOLEAN bNLSinit = FALSE;
  1461.  
  1462. static void InitNLS( void )
  1463.     {
  1464.     int i, uppercaseChar;
  1465.     COUNTRYCODE countryCode;
  1466.  
  1467.     /* Flag the fact that the xlate tables are initialized */
  1468.     bNLSInit = TRUE;
  1469.  
  1470.     /* Set up default tables */
  1471.     for( i = 0; i < 256; i++ )
  1472.         cUCtbl[ i ] = cLCtbl[ i ] = ( unsigned char ) i;
  1473.  
  1474.     /* Set up map table */
  1475.     countryCode.country = countryCode.codepage = 0;
  1476.     DosMapCase( sizeof( cUCtbl ), &countryCode, ( PCHAR ) cUCtbl );
  1477.  
  1478.     for( i = 0; i < 256; i++ )
  1479.         if( ( uppercaseChar = cUCtbl[ i ] ) != i && \
  1480.             cLCtbl[ uppercaseChar ] == ( unsigned char ) uppercaseChar )
  1481.             cLCtbl[ uppercaseChar ] = ( unsigned char ) i;
  1482.  
  1483.     for( i = 'A'; i <= 'Z'; i++ )
  1484.         cLCtbl[ i ] = ( unsigned char ) ( i - 'A' + 'a' );
  1485.     }
  1486.  
  1487. void strlwr( char *string )
  1488.     {
  1489.     char *strPtr = string;
  1490.  
  1491.     if( !bNLSinit )
  1492.         InitNLS();
  1493.  
  1494.     while( *strPtr )
  1495.         *strPtr = cLowerCase[ ( int ) *strPtr ];
  1496.     }
  1497.  
  1498. int strnicmp( char *src, char *dest, int length )
  1499.     {
  1500.     char srcLower[ length ];    /* Note cool GNUC variable length array! */
  1501.     char destLower[ length ];    /* Note cool GNUC variable length array! */
  1502.  
  1503.     strlwr( strcpy( srcLower, src ) );
  1504.     strlwr( strcpy( destLower, dest ) );
  1505.     return( strncmp( srcLower, destLower, length ) );
  1506.     }
  1507.  
  1508. #endif /* __gcc && !__EMX__ */
  1509.  
  1510. #endif /* OS2_32 */
  1511.